home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 211_01 / xmerger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-01-01  |  11.9 KB  |  652 lines

  1. /* XMERGER.C   VERS:- 01.00  DATE:- 09/26/86  TIME:- 09:37:42 PM */
  2. /*
  3. %CC1 $1.C -O -X -E6000
  4. %CLINK $1 DIO -F CHARFUN STRFUN -S -E6000
  5. %DELETE $1.CRL 
  6. */
  7. /* 
  8. Description:
  9.  
  10. Merge two sorted files, with output redirection.
  11.  
  12. The files must be sorted on the same key used in the merge.
  13. The key can be a sequence of digit fields.
  14. The key length can be specified.
  15. The key start can be defined by a string each record is searched for.
  16.  
  17. Records can be of variable length, defined by a delimiter string,
  18. eg "\n" if each line is a record.
  19. Records can be multiline.
  20.  
  21. Various options:  see help_mess() for summary.
  22. For usage:  see help_mess().
  23.  
  24.  
  25. The logic is adapted from that of MERGE, from the Van Nuys Toolkit, 
  26. by Eugene H. Mallory.
  27. The function decode() is adapted from code in SEARCH, from the
  28. Van Nuys Toolkit.
  29.  
  30.  
  31. By J.A. Rupley, Tucson, Arizona
  32. Coded for BDS C compiler, version 1.50a
  33. */
  34.  
  35. #include "BDSCIO.H"
  36. #include "DIO.H"
  37.  
  38. #define BUFLEN     60*128
  39.  
  40. FILE fcb;
  41. char buf1[BUFLEN], buf2[BUFLEN], *s1, *s2;
  42. char delim[MAXLINE], pattern[MAXLINE];
  43. char digits1[MAXLINE], digits2[MAXLINE];
  44. char filename[20];
  45. int flag1, flag2;
  46. int xi, xj;
  47. int flag;
  48. int upper_case, reverse, column, length, file_only, input_only, duplicate;
  49. int merge, num_only, reject, title, unique;
  50. int optionerr;
  51.  
  52. main(argc, argv)
  53. char **argv;
  54. int argc;
  55.  
  56. {
  57.     dioinit(&argc, argv);
  58.  
  59.     flag = flag1 = flag2 = 0;
  60.  
  61.     /*for standard merge*/
  62.     /*
  63.         column = length = 0;
  64.         merge = 1;
  65.         upper_case = 0;
  66.         reverse = 0;
  67.         unique = 0;
  68.         num_only = 0;
  69.         reject = 0;
  70.         title = 0;
  71.         strcpy(delim, "\n");
  72.         *pattern = '\0';
  73.     */
  74.  
  75.     /*for CAS files = default setup*/
  76.     column = 0;
  77.     length = 20;
  78.     merge = 0;
  79.     upper_case = 0;
  80.     reverse = 1;
  81.     unique = 1;
  82.     num_only = 1;
  83.     reject = 1;
  84.     title = 3;
  85.     strcpy(delim, "\n\*");
  86.     strcpy(pattern, "AN  CA");
  87.  
  88.     get_options(&argc, argv);
  89.     if (optionerr)
  90.         help_mess();
  91.     if (argc < 2)
  92.     {
  93.         typef("XMERGE: No file name given.\n");
  94.         help_mess();
  95.     }
  96.     if (fopen(argv[1], fcb) == -1)
  97.         error("MERGE: Unable to open file %s.", argv[1]);
  98.     strcpy(filename, argv[1]);
  99.  
  100.     if (length == 0)
  101.         length = BUFLEN;
  102.     if (column > 0)
  103.         column--;
  104.     if (duplicate || file_only || input_only)
  105.         merge = unique = 0;
  106.     if (unique)
  107.         merge = input_only = file_only = duplicate = 0;
  108.     if (merge)
  109.         input_only = file_only = duplicate = 0;
  110.     if (!*pattern)
  111.         reject = 0;
  112.  
  113.     getinput();
  114.     getfile();
  115.     while (TRUE)
  116.     {
  117.         flag = string_compare(s1, s2);
  118.         if (flag == 0)
  119.         {
  120.             if (unique || duplicate)
  121.             {
  122.                 putrec(3, buf1);
  123.                 *buf1 = *buf2 = '\0';
  124.                 getinput();
  125.                 getfile();
  126.             }
  127.             else
  128.                 if (merge)
  129.             {
  130.                 putrec(1, buf1);
  131.                 *buf1 = '\0';
  132.                 getinput();
  133.             }
  134.             else
  135.                 if (input_only || file_only)
  136.             {
  137.                 *buf1 = *buf2 = '\0';
  138.                 getinput();
  139.                 getfile();
  140.             }
  141.         }
  142.         else
  143.             if (flag > 0)
  144.         {
  145.             if (unique || merge || file_only)
  146.                 putrec(2, buf2);
  147.             *buf2 = '\0';
  148.             getfile();
  149.         }
  150.         else
  151.             {
  152.             if (unique || merge || input_only)
  153.                 putrec(1, buf1);
  154.             *buf1 = '\0';
  155.             getinput();
  156.         }
  157.     }
  158. }
  159.  
  160.  
  161. void putrec(input, buffer)
  162. int input;
  163. char *buffer;
  164. {
  165.     if (title && *buffer)
  166.     {
  167.         if (*buffer == '\f' || *buffer == '\n')
  168.             while (*buffer == '\f' || *buffer == '\n')
  169.                 putchar(*buffer++);
  170.         else
  171.             putchar('\n');
  172.         if ((title > 1) && (input > 1))
  173.         {
  174.             puts(filename);
  175.             putchar('\n');
  176.         }
  177.         if ((title % 2) && (input % 2))
  178.         {
  179.             puts(_infile);
  180.             putchar('\n');
  181.         }
  182.     }
  183.     while (*buffer)
  184.         putchar(*buffer++);
  185. }
  186.  
  187.  
  188. int bufx_fill(input, sx, bufx, flagx)
  189. char **sx, *bufx;
  190. int input, *flagx;
  191. {
  192.     char *p_delim;
  193.     int c2, c, i;
  194.  
  195. restart :
  196.     *sx = bufx[0] = '\0';
  197.     i = 0;
  198.     p_delim = delim;
  199.  
  200.     while (i < BUFLEN)
  201.     {
  202.         if (*flagx)
  203.             return 0;
  204.         if (input == 2)
  205.         {
  206.             if ((c = getc(fcb)) == '\r')
  207.             {
  208.                 if ((c2 = getc(fcb)) == '\n')
  209.                     c = c2;
  210.                 else
  211.                     ungetc(c2, fcb);
  212.             }
  213.         }
  214.         else
  215.             if (input == 1)
  216.             c = getchar();
  217.         else
  218.             error("XMERGE: wrong input identifier.");
  219.         if ((c == EOF) || (c == CPMEOF))
  220.         {
  221.             *flagx = 1;
  222.             bufx[i] = '\0';
  223.             if (i)
  224.                 strcat(bufx, delim);
  225.             set_sx(input, sx, bufx);
  226.             if (!*sx && reject)
  227.                 goto restart;
  228.             return 1;
  229.         }
  230.         bufx[i++] = c;
  231.         if (c == *p_delim)
  232.         {
  233.             if (!*++p_delim)
  234.             {
  235.                 bufx[i] = '\0';
  236.                 set_sx(input, sx, bufx);
  237.                 if (!*sx && reject)
  238.                     goto restart;
  239.                 return 1;
  240.             }
  241.         }
  242.         else
  243.             p_delim = delim;
  244.     }
  245.     error("XMERGE: record overflows buffer.");
  246. }
  247.  
  248.  
  249. void set_sx(input, sx, bufx)
  250. int input;
  251. char **sx, *bufx;
  252. {
  253.     int temp;
  254.  
  255.     if (strlen(pattern) == 0)
  256.         *sx = bufx;
  257.     else
  258.         if (temp = str1_in_str2(pattern, bufx))
  259.             *sx = bufx + temp;
  260.         else
  261.             *sx = 0;
  262.     return;
  263. }
  264.  
  265.  
  266. void getinput()
  267. {
  268.     if (!bufx_fill(1, &s1, buf1, &flag1))
  269.         inputeof();
  270. }
  271.  
  272.  
  273. void getfile()
  274. {
  275.     if (!bufx_fill(2, &s2, buf2, &flag2))
  276.         fileeof();
  277. }
  278.  
  279.  
  280. void inputeof()
  281. {
  282.     if (unique || merge || file_only)
  283.     {
  284.         do
  285.             {
  286.             putrec(2, buf2);
  287.         }
  288.         while (bufx_fill(2, &s2, buf2, &flag2))
  289.             ;
  290.     }
  291.     dioflush();
  292.     exit();
  293. }
  294.  
  295.  
  296. void fileeof()
  297. {
  298.     fclose(fcb);
  299.     if (unique || merge || input_only)
  300.     {
  301.         do
  302.             {
  303.             putrec(1, buf1);
  304.         }
  305.         while (bufx_fill(1, &s1, buf1, &flag1))
  306.             ;
  307.     }
  308.     dioflush();
  309.     exit();
  310. }
  311.  
  312.  
  313.         /*page eject*/
  314.  
  315. int num_compare(t1, t2)
  316. char *t1, *t2;
  317. {
  318.     int lenx, temp, index1, index2;
  319.  
  320.     lenx = index1 = index2 = 0;
  321.     digits1[0] = digits2[0] = '\0';
  322.  
  323.     if (!*t1 && !*t2)
  324.         return 0;
  325.     else
  326.         if (!*t1)
  327.         return -1;
  328.     else
  329.         if (!*t2)
  330.         return 1;
  331.  
  332.     while (*t1 && (!isdigit(*t1) || (*t1 == '0')))
  333.         t1++;
  334.     while (isdigit(*t1))
  335.     {
  336.         digits1[index1++] = *t1;
  337.         t1++;
  338.     }
  339.  
  340.     while (*t2 && (!isdigit(*t2) || (*t2 == '0')))
  341.         t2++;
  342.     while (isdigit(*t2))
  343.     {
  344.         digits2[index2++] = *t2;
  345.         t2++;
  346.     }
  347.     digits1[index1] = digits2[index2] = '\0';
  348.  
  349.     lenx = ((t1 - s1) > (t2 - s2)) ? (t1 - s1) : (t2 - s2);
  350.     if (temp = (index1 - index2))
  351.         return temp;
  352.     if (temp = strcmp(digits1, digits2))
  353.         return temp;
  354.     if (lenx > (length + column))
  355.         return 0;
  356.     return num_compare(t1, t2);
  357. }
  358.  
  359.  
  360. int string_compare(t1, t2)
  361. char *t1, *t2;
  362. {
  363.     int i;
  364.     if ((strlen(t1) <= column) && (strlen(t2) <= column))
  365.         return 0;
  366.     if (strlen(t1) <= column)
  367.     {
  368.         if (!reverse)
  369.             return -1;
  370.         else
  371.             return 1;
  372.     }
  373.     if (strlen(t2) <= column)
  374.     {
  375.         if (!reverse)
  376.             return 1;
  377.         else
  378.             return -1;
  379.     }
  380.     if (num_only)
  381.     {
  382.         t1 = t1 + column;
  383.         t2 = t2 + column;
  384.         if (!reverse)
  385.             return num_compare(t1, t2);
  386.         else
  387.             return -num_compare(t1, t2);
  388.     }
  389.     if (upper_case)
  390.     {
  391.         for (i = column; i < column + length; i++)
  392.         {
  393.             if (toupper(t1[i]) != toupper(t2[i]))
  394.                 if (!reverse)
  395.                     return toupper(t1[i]) - toupper(t2[i]);
  396.             else
  397.                 return toupper(t2[i]) - toupper(t1[i]);
  398.             if (t1[i] == '\0')
  399.                 return 0;
  400.         }
  401.         return 0;
  402.     }
  403.     else
  404.         {
  405.         for (i = column; i < column + length; i++)
  406.         {
  407.             if (t1[i] != t2[i])
  408.             {
  409.                 if (!reverse)
  410.                     return t1[i] - t2[i];
  411.                 else
  412.                     return t2[i] - t1[i];
  413.             }
  414.             if (t1[i] == '\0')
  415.                 return 0;
  416.         }
  417.         return 0;
  418.     }
  419. }
  420.  
  421.  
  422. /*
  423. the next two functions perform as follows:
  424. if string 1 is found in string2, return the position of the character 
  425. in str2 immediately following the str1 sequence;
  426. else 0 is returned
  427. */
  428.  
  429. int str1_in_str2(str1, str2)
  430. char *str1, *str2;
  431. {
  432.     int i, loc;
  433.  
  434.     for (i = 0; i < strlen(str2); i++)
  435.         if (loc = str1_start_str2(str1, &str2[i]))
  436.             return (loc + i);
  437.     return 0;
  438. }
  439.  
  440.  
  441. int str1_start_str2(str1, str2)
  442. char *str1, *str2;
  443. {
  444.     int loc;
  445.  
  446.     loc = 0;
  447.     while (toupper(*str1++) == toupper(*str2++))
  448.     {
  449.         loc++;
  450.         if (!*str1)
  451.             return loc;
  452.         if (!*str2)
  453.             return 0;
  454.     }
  455.     return 0;
  456. }
  457.  
  458.  
  459. void setuppat(pat, str)
  460. char *pat;
  461. char *str;
  462. {
  463.     int c;
  464.  
  465.     xj = xi = 0;
  466.  
  467.     while (c = pat[xi++])
  468.         decode(c, pat, str, 0);
  469.     str[xj] = 0;
  470.     return;
  471. }
  472.  
  473.  
  474. int decode(c, pat, str, not_flag)
  475. int c, not_flag;
  476. char *pat, *str;
  477. {
  478.     switch (c)
  479.     {
  480.     case '_' :
  481.         str[xj++] = ' ';
  482.         break;
  483.     case '^' :
  484.         c = pat[xi++];
  485.         if (c > 0x7f || c <= 0x40)
  486.             error("SEARCH: illegal character follows ^");
  487.         str[xj++] = toupper(c) - 0x40;
  488.         break;
  489.     case '\\' :
  490.         c = pat[xi++];
  491.         if (c == 0)
  492.             error("SEARCH: \\ requires character following.");
  493.         switch (c)
  494.         {
  495.         case 'N' :
  496.             c = '\n';
  497.             break;
  498.         case 'F' :
  499.             c = '\f';
  500.             break;
  501.         case 'R' :
  502.             c = '\r';
  503.             break;
  504.         case 'T' :
  505.             c = '\t';
  506.             break;
  507.         case 'B' :
  508.             c = '\b';
  509.             break;
  510.         }
  511.         if (isdigit(c))
  512.             c = c - '0';
  513.         str[xj++] = c;
  514.         break;
  515.     default :
  516.         str[xj++] = c;
  517.     }
  518.     return;
  519. }
  520.  
  521.  
  522. void help_mess()
  523. {
  524.     typef("USAGE:  xmerge  <fn1  fn2  [redir: >fn3 etc]  [options: -p.. -d.. etc]\n");
  525.     typef("    fn1 and fn2 must be sorted on the key tested in the merge.\n");
  526.     typef("XMERGE: Legal options:\n");
  527.     typef("    default setup = CAS files;  false = 0;  _, \\x, and ^x  OK in strings.\n");
  528.     typef("    options = true/false toggles, unless value(n)/string(str) indicated.\n");
  529.     typef("-Sn=1    Select for:   CAS files (n=1);   standard merge (n=0).\n");
  530.     typef("         =1  for CAS files;           =0  for standard merge.\n");
  531.     typef("         the Sn option, if used, must be last.\n");
  532.     typef("-U=0     Upper case compares.         -R=1     Reverse sort.\n");
  533.     typef("-I=0     Output non-matching (fn1)    -F=0     Output non-matching (fn2).\n");
  534.     typef("-A=1     Output unique (fn1 and fn2)  -B=0     Output duplicates (fn1 & fn2).\n");
  535.     typef("-X=1     Reject record if it contains no Pstring.\n");
  536.     typef("-#=1     Digit sequences only used in string compares.\n");
  537.     typef("-Cn=0    Column position to begin compare.\n");
  538.     typef("-Ln=10   Length of string to compare (0 => BUFLEN = ca 8K).\n");
  539.     typef("-Tn=3    Type filenames at head of record:\n");
  540.     typef("         =1|3  for fn1;    =2|3  for fn2;    =0  for no header written.\n");
  541.     typef("-Dstr    Delimiter string for record:\n");
  542.     typef("         =\\n\\*   for CAS files;       =\\n   for standard merge\n");
  543.     typef("-Pstr    Pattern at end of which start compare:\n");
  544.     typef("         =AN__CA   for CAS files;     =\\0   for standard merge");
  545.     exit(0);
  546. }
  547.  
  548.  
  549. void get_options(argcpntr, argv)
  550. char **argv;
  551. int *argcpntr;
  552. {
  553.     int ii, jj;
  554.     char *ss;
  555.  
  556.     optionerr = 0;
  557.  
  558.     for (ii = *argcpntr - 1; ii > 0; ii--)
  559.         if (argv[ii][0] == '-')
  560.         {
  561.             ss = &argv[ii][1];
  562.  
  563.             switch (toupper(*ss++))
  564.             {
  565.             case 'U' :
  566.                 upper_case = !upper_case;
  567.                 break;
  568.             case 'R' :
  569.                 reverse = !reverse;
  570.                 break;
  571.             case 'I' :
  572.                 input_only = !input_only;
  573.                 break;
  574.             case 'F' :
  575.                 file_only = !file_only;
  576.                 break;
  577.             case 'A' :
  578.                 unique = !unique;
  579.                 break;
  580.             case 'B' :
  581.                 duplicate = !duplicate;
  582.                 break;
  583.             case 'X' :
  584.                 reject = !reject;
  585.                 break;
  586.             case '#' :
  587.                 num_only = !num_only;
  588.                 break;
  589.             case 'S' :
  590.                 if (*ss == '0')
  591.                 {
  592.                     column = length = 0;
  593.                     merge = 1;
  594.                     upper_case = 0;
  595.                     reverse = 0;
  596.                     unique = 0;
  597.                     num_only = 0;
  598.                     reject = 0;
  599.                     title = 0;
  600.                     strcpy(delim, "\n");
  601.                     *pattern = '\0';
  602.                     break;
  603.                 }
  604.                 if (*ss == '1')
  605.                 {
  606.                     column = 0;
  607.                     length = 20;
  608.                     merge = 0;
  609.                     upper_case = 0;
  610.                     reverse = 1;
  611.                     unique = 1;
  612.                     num_only = 1;
  613.                     reject = 1;
  614.                     title = 3;
  615.                     strcpy(delim, "\n\*");
  616.                     strcpy(pattern, "AN  CA");
  617.                     break;
  618.                 }
  619.             case 'C' :
  620.                 column = atoi(ss);
  621.                 break;
  622.             case 'L' :
  623.                 length = atoi(ss);
  624.                 break;
  625.             case 'T' :
  626.                 title = atoi(ss);
  627.                 break;
  628.             case 'D' :
  629.                 setuppat(ss, delim);
  630.                 break;
  631.             case 'P' :
  632.                 setuppat(ss, pattern);
  633.                 break;
  634.             case 'H' :
  635.                 optionerr = TRUE;
  636.                 break;
  637.             default :
  638.                 typef("XMERGE: Illegal option %c.\n"
  639.                     , *--ss);
  640.                 ss++;
  641.                 optionerr = TRUE;
  642.                 break;
  643.             }
  644.  
  645.             for (jj = ii; jj < (*argcpntr - 1); jj++)
  646.                 argv[jj] = argv[jj + 1];
  647.             (*argcpntr)--;
  648.         }
  649. }
  650.  
  651.  
  652.